package com.literature.search.file.task.executor;

import com.literature.search.core.entity.*;
import com.literature.search.core.enums.FileFormatEnum;
import com.literature.search.core.utils.OcrUtil;
import com.literature.search.core.utils.PdfUtil;
import com.literature.search.core.utils.SpringApplicationContext;
import com.literature.search.file.service.IElasticService;
import com.literature.search.file.service.IFileService;
import com.literature.search.file.task.data.TaskData;
import com.literature.search.file.task.exception.TaskRunException;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author: DangKong
 * @Date: 2023/3/2 21:02
 * @Description:
 */
@Slf4j
public class TaskExecutor {

    public void execute(TaskData taskData) throws TaskRunException, IOException, TesseractException {  // 任务执行

        // 第一步下载文件，转换为输入流
        FileDocument fileDocument = taskData.getFileDocument(); // 获取文件文档对象
        InputStream docInputStream = new ByteArrayInputStream(downFileBytes(fileDocument.getGridfsId()));

        // 第二步 处理pdf文件中的文本
        handleFile(docInputStream,taskData);

        // 第三步 将文本索引到es中
        try {
            uploadFileToEs(taskData);
        } catch (Exception e) {
            throw new TaskRunException("建立索引的时候出错!", e);
        }
    }


    public void handleFile(InputStream is, TaskData taskData) throws IOException, TesseractException {
        FileDocument fileDocument = taskData.getFileDocument();
        //为pdf的每一页生成一个txt文件和一个图片文件,并且提取图片
        Map<String,Object> map = handleText(is, fileDocument);

        List<String> txtFilePathList = (List<String>) map.get("txtFilePathList"); // 每一页pdf的文本文件路径
        List<String> thumbPageFilePathList = (List<String>) map.get("thumbPageFilePathList");  // 每一页pdf的缩略图路径
        taskData.setTxtFilePathList(txtFilePathList);
        taskData.setThumbPageFilePathList(thumbPageFilePathList);
        taskData.setThumbFilePath(thumbPageFilePathList.get(0));          //首页缩略图路径为第一页的缩略图路径
        fileDocument.setIsEnglish((Boolean) map.get("isEnglish")); // 设置是否是英文文档

        List<String> pngFilePathList = (List<String> ) map.get("pngFilePathList"); // 提取出来的图片路径
        taskData.setPngFilePathList(pngFilePathList);


        handleDescription(txtFilePathList.get(0),fileDocument); // 添加文档描述

        int textFileCount = txtFilePathList.size();
        String textFilePath, picPath;
        ArrayList<PageContent> pageContents = new ArrayList<>(textFileCount); // 每一页的文本内容

        IFileService fileService = SpringApplicationContext.getBean(IFileService.class);

        for (int i = 0; i < textFileCount; i++) {
            PageContent pageContent = new PageContent();
            pageContent.setFileId(fileDocument.getId()); // 设置文档id
            pageContent.setPageNumber(i+ 1); // 设置页码

            textFilePath = txtFilePathList.get(i); // 获取文本文件路径
            picPath = thumbPageFilePathList.get(i); // 获取缩略图路径
            if (!new File(textFilePath).exists() && !new File(picPath).exists()) {
                throw new TaskRunException("文本文件或图片不存在，需要进行重新提取");
            }

            // 文本、缩略图图片上传到gridFS系统中
            try (
                    FileInputStream thumbIns = new FileInputStream(picPath)  // 读取缩略图文件
            ) {

                pageContent.readOriginText(textFilePath); // 读取文本文件
                String thumbId = fileService.uploadFileToGridFs(
                        FileFormatEnum.PNG.getFilePrefix(),
                        thumbIns,
                        FileFormatEnum.PNG.getContentType());
                pageContent.setThumbId(thumbId);
                if (i == 0) {
                    fileDocument.setThumbId(thumbId); // 设置缩略图的id
                }
                pageContents.add(pageContent);
            }
            catch (IOException e) {
                throw new TaskRunException("存储文本文件或缩略图文件报错了，请核对", e);
            }

            // 删除临时文件
            try {
                Files.delete(Paths.get(textFilePath)); // 删除文本文件
                Files.delete(Paths.get(picPath)); // 删除缩略图文件
            } catch (IOException e) {
                log.error("删除文件路径{} ==> 失败信息{}", textFilePath, e);
                log.error("删除文件路径{} ==> 失败信息{}", picPath, e);
            }
        }
        ArrayList<PictureParse> pictureParses = new ArrayList<>(pngFilePathList.size());
        for(String pngPath : pngFilePathList){
            PictureParse pictureParse = new PictureParse();
            // 解析字符串，获取图片所在的页码，页面为p
            int pageNum = Integer.parseInt(pngPath.substring(pngPath.lastIndexOf("_") - 1, pngPath.lastIndexOf("_")));
            pictureParse.setFileId(fileDocument.getId());
            pictureParse.setPageNum(pageNum);
            //pictureParse.readOCRContent(OcrUtil.parseText(pngPath));
            pictureParse.setOcrContent(OcrUtil.parseText(pngPath));
            //将图片上传到gridFS系统中
            try(
                    FileInputStream pngInputStream = new FileInputStream(pngPath)
            ){
                String pngId = fileService.uploadFileToGridFs(
                        FileFormatEnum.PNG.getFilePrefix(),
                        pngInputStream,
                        FileFormatEnum.PNG.getContentType());
                pictureParse.setGridfsId(pngId);
                pictureParses.add(pictureParse);

            } catch (IOException e) {
                throw new TaskRunException("存储pdf提取的图片报错了，请核对", e);
            }
            // 删除临时文件
            try {
                Files.delete(Paths.get(pngPath)); // 删除图片文件
            } catch (IOException e) {
                log.error("删除文件路径{} ==> 失败信息{}", pngPath, e);
            }

        }

        fileDocument.setPictureParseList(pictureParses);
        fileDocument.setPageContentList(pageContents);

    }






    public void uploadFileToEs(TaskData taskData) {
        FileDocument fileDocument = taskData.getFileDocument();
        try {
            EsFileObject fileObj = new EsFileObject();
            fileObj.setId(fileDocument.getId()); // 设置文档id
            fileObj.setFileName(fileDocument.getFileName()); // 设置文档名称
            fileObj.setThumbId(fileDocument.getThumbId()); // 设置缩略图id
            fileObj.setUploadDate(fileDocument.getUploadDate()); // 设置上传时间
            fileObj.setUploadUser(fileDocument.getUserName()); // 设置上传用户
            fileObj.setLike(fileDocument.getLike()); // 设置点赞数
            fileObj.setDownload(fileDocument.getDownload()); // 设置下载数
            fileObj.setView(fileDocument.getView()); // 设置浏览数
            fileObj.setCollect(fileDocument.getCollect()); // 设置收藏数
            fileObj.setIsEnglish(fileDocument.getIsEnglish()); // 设置是否是英文文档


            ArrayList<EsPageObject> esPageObjects = new ArrayList<>();
            fileDocument.getPageContentList().forEach(pageContent -> {
                EsPageObject esPageObject = new EsPageObject();
                esPageObject.setId(pageContent.getThumbId()); // 设置这一页内容的缩略图id
                esPageObject.setPageNumber(pageContent.getPageNumber()); // 设置页码
                esPageObject.setContent(pageContent.getContent()); // 设置文本内容
                esPageObject.setTag("文本"); // 设置标签
                esPageObjects.add(esPageObject);
            });
            fileObj.setPageContents(esPageObjects);

            ArrayList<EsPicObject> esPicObjects = new ArrayList<>();
            fileDocument.getPictureParseList().forEach(pictureParse -> {
                EsPicObject esPicObject = new EsPicObject();
                esPicObject.setId(pictureParse.getGridfsId()); // 设置图片id
                esPicObject.setPageNumber(pictureParse.getPageNum()); // 设置页码
                esPicObject.setContent(pictureParse.getOcrContent()); // 设置ocr识别的内容
                esPicObject.setTag("图片"); // 设置标签
                esPicObjects.add(esPicObject);
            });
            fileObj.setPicContents(esPicObjects);

            // 上传到es中
            SpringApplicationContext.getBean(IElasticService.class).insert(fileObj);



        } catch (TaskRunException e) {
            throw new TaskRunException("存入es的过程中报错了", e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }



    /**
     * @Description 设置描述内容 TODO:设置为摘要
     * @Param [textFilePath, fileDocument]
     **/
    private void handleDescription(String textFilePath, FileDocument fileDocument) {
        try{

            List<String> stringList = FileUtils.readLines(new File(textFilePath),
                    StandardCharsets.UTF_8);
            String str = null;
            if (!stringList.isEmpty()) {
                str = stringList.get(0);
            }
            if (str == null) {
                str = "No description";
            } else if (str.length() > 300) {
                str = str.substring(0, 300);
            }
            fileDocument.setDescription(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * @return byte[]
     * @Description  从gridFS 系统中下载文件为字节流
     * @Param [gridFsId]
     **/
    protected byte[] downFileBytes(String gridFsId) {
        IFileService fileService = SpringApplicationContext.getBean(IFileService.class);
        return fileService.getFileBytes(gridFsId);
    }



    private Map<String, Object> handleText(InputStream is, FileDocument fileDocument) {
        return PdfUtil.handlePdfText(is, fileDocument);
    }

}
